namespace SimpleWebServices.Net
{
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Mime;
    using System.Text;

    public class Response
    {
        private WebHeaderCollection _headers;
        private CookieCollection _cookies;
        private AbsoluteUri _location;

        public Response(HttpStatusCode status, AbsoluteUri location, WebHeaderCollection headers, CookieCollection cookies)
        {
            this.Status = status;
            this.Location = location;
            this.Headers = headers;
            this.Cookies = cookies;
        }

        public WebHeaderCollection Headers
        {
            get
            {
                return this._headers;
            }

            private set
            {
                if (null == value)
                {
                    throw new ArgumentNullException("value");
                }

                this._headers = value;
            }
        }

        public CookieCollection Cookies
        {
            get
            {
                return this._cookies;
            }

            private set
            {
                if (null == value)
                {
                    throw new ArgumentNullException("value");
                }

                this._cookies = value;
            }
        }

        public AbsoluteUri Location
        {
            get
            {
                return this._location;
            }

            private set
            {
                if (null == value)
                {
                    throw new ArgumentNullException("value");
                }

                this._location = value;
            }
        }

        public HttpStatusCode Status
        {
            get;
            private set;
        }

        public static Response ToTypedContent(HttpWebResponse response)
        {
            Response result = null;

            if (string.IsNullOrEmpty(response.ContentType))
            {
                result = new BinaryResponse(response);
            }
            else
            {
                ContentType type = new ContentType(response.ContentType);
                if (type.MediaType.StartsWith("text/plain", StringComparison.OrdinalIgnoreCase))
                {
                    result = new TextPlainResponse(response);
                }
                else if (type.MediaType.StartsWith("text/html", StringComparison.OrdinalIgnoreCase))
                {
                    result = new HtmlResponse(response);
                }
                else if (type.MediaType.StartsWith("text/xml", StringComparison.OrdinalIgnoreCase)
                    || type.MediaType.StartsWith("application/xml", StringComparison.OrdinalIgnoreCase)
                    || (type.MediaType.StartsWith("application/", StringComparison.OrdinalIgnoreCase) && type.MediaType.EndsWith("+xml", StringComparison.OrdinalIgnoreCase)))
                {
                    result = new XmlResponse(response);
                }
                else
                {
                    result = new BinaryResponse(response);
                }
            }

            return result;
        }

        public static WebResponse Http(HttpRequestDefinition definition)
        {
            return Response.Http(definition, null as IHttpContent);
        }

        public static WebResponse Http(HttpRequestDefinition definition, IHttpContent content)
        {
            if (null == definition)
            {
                throw new ArgumentNullException("definition");
            }

            WebResponse result = null;
            try
            {
                WebRequest request = definition.ToWebRequest();
                using (Stream input = (null == content) ? null as Stream : request.GetRequestStream())
                {
                    if (null != content)
                    {
                        request.ContentType = content.Type.MediaType;
                        content.Write(input);
                    }

                    result = request.GetResponse();
                }
            }
            catch (WebException exception)
            {
                result = exception.Response;
            }

            return result;
        }

        public override string ToString()
        {
            StringBuilder buffer = new StringBuilder();
            buffer.AppendLine(this.Location);
            buffer.Append(Environment.NewLine);
            buffer.Append("HTTP/1.1 ");
            buffer.Append((int)this.Status);
            buffer.Append(" ");
            buffer.Append(this.Status.ToString("g"));
            buffer.Append(Environment.NewLine);
            for (int i = 0; i < this.Headers.Count; i++)
            {
                buffer.Append(this.Headers.Keys[i]);
                buffer.Append(": ");
                buffer.Append(this.Headers[i]);
                buffer.Append(Environment.NewLine);
            }

            return buffer.ToString();
        }
    }
}